// OpAnnotationDwgCircle

import {
  Vector3,
  Font,
  Scene,
  Shape,
  ShapeGeometry,
  Mesh,
  Path,
  Vector2,
} from "../../WebViewer/THREE/Three";
import { AnnotationMesh, OpAnnotationDwg } from "./OpAnnotationDwg";

class OpAnnotationDwgCircle extends OpAnnotationDwg {
  constructor(app: any) {
    super(app);
  }

  tempAnnotationPointerUp() {
    if (!this.tempAnnotation) return;
    const length = this.tempAnnotation.ptsArr.length - 1;
    let start = this.tempAnnotation.ptsArr[length - 1].clone();
    let end = this.tempAnnotation.ptsArr[length].clone();
    let distance = start.distanceTo(end);
    if (distance === 0) return;

    super.stopAnnotation();
  }

  createNewAnnotation(point: Vector3) {
    const scene = this.app.bimViewer.getIncrementalScene();
    const font = this.app.bimViewer.getRenderContext().getWebGLFont();
    const mesh = new AnnotationCircleMesh({
      start: point,
      end: point,
      font,
      scene,
      lineSize: this.lineSize,
      textSize: this.textSize,
      color: this.color,
    });
    return mesh;
  }

  createAnnotationFromData(data: {
    ptsArr: Array<number[]>;
    lineSize: number;
    textSize: number;
    color: string;
  }) {
    let pointArr: Vector3[] = [];
    data.ptsArr.forEach((item: number[]) => {
      const v3 = new Vector3().fromArray(item);
      pointArr.push(v3);
    });

    const scene = this.app.bimViewer.getIncrementalScene();
    const font = this.app.bimViewer.getRenderContext().getWebGLFont();
    const mesh = new AnnotationCircleMesh({
      start: pointArr[0],
      end: pointArr[1],
      font,
      scene,
      lineSize: data.lineSize,
      textSize: data.textSize,
      color: data.color,
    });

    const pixelScale2d = this.app.bimViewer.mainCamera.getPixelScale2d();
    mesh.updateLineTextShape(pixelScale2d);

    mesh.setDragHandleVisible(false);

    return mesh;
  }
}

class AnnotationCircleMesh extends AnnotationMesh {
  constructor(param: {
    start: Vector3;
    end: Vector3;
    font: Font;
    scene: Scene;
    lineSize: number;
    textSize: number;
    color: string;
  }) {
    super(param);

    this._createLineTextShape();
  }

  private _createLineTextShape() {
    const shape = new Shape();
    const shapeGeo = new ShapeGeometry(shape);
    this.lineShape = new Mesh(shapeGeo, this.material);
    this.scene.add(this.lineShape);

    this.ptsArr.forEach((point) => {
      const drag = this.createDragHandle(point);
      this.dragHandleArr.push(drag);
      drag.install(this.scene);
    });
  }

  updateLineTextShape(pixelScale2d: number) {
    pixelScale2d = pixelScale2d * (this.lineSize + 1);
    if (pixelScale2d < 0.00099) pixelScale2d = 0.00099;

    const startP = new Vector2(
      Math.min(this.ptsArr[0].x, this.ptsArr[1].x),
      Math.max(this.ptsArr[0].y, this.ptsArr[1].y)
    );
    const endP = new Vector2(
      Math.max(this.ptsArr[0].x, this.ptsArr[1].x),
      Math.min(this.ptsArr[0].y, this.ptsArr[1].y)
    );

    const centerX = (startP.x + endP.x) / 2;
    const centerY = (startP.y + endP.y) / 2;
    const a = Math.abs((endP.x - startP.x) / 2);
    const b = Math.abs((endP.y - startP.y) / 2);

    const shape = new Shape();
    for (let i = 0; i <= 2 * Math.PI; i += 0.01) {
      const x = a * Math.cos(i);
      const y = b * Math.sin(i);
      if (i === 0) {
        shape.moveTo(x + centerX, y + centerY);
      } else {
        shape.lineTo(x + centerX, y + centerY);
      }
    }
    shape.closePath();

    const holePath = new Path();
    for (let i = 0; i <= 2 * Math.PI; i += 0.01) {
      const x = (a - pixelScale2d) * Math.cos(i);
      const y = (b - pixelScale2d) * Math.sin(i);
      if (i === 0) {
        holePath.moveTo(x + centerX, y + centerY);
      } else {
        holePath.lineTo(x + centerX, y + centerY);
      }
    }
    holePath.closePath();

    shape.holes.push(holePath);

    const shapeGeo = new ShapeGeometry(shape);
    this.lineShape.geometry.dispose();
    this.lineShape.geometry = shapeGeo;
  }
}

export { OpAnnotationDwgCircle };
